#!/usr/bin/perl -w

BEGIN   
{
	sub getPoints{return '../../' if (!$_[1]);return '../' if (!$_[0]);return '/';}
	(my $file = __FILE__) =~ s/\/?(modules\/)?(http_bandwidth\/)?(\w+\.pl)$/&getPoints($1,$2)/e;
	$file = './' if $file eq '/';
	unshift(@INC, $file."bin");
	unshift(@INC, $file."modules/http_bandwidth");
	unshift(@INC, $file."modules/http_logging");
	unshift(@INC, $file."modules/http_ip_limit");
}

use strict;
use TWM;
use Bandwidth;
use Logging;
use IPLimit;

my $objBandWidth = Bandwidth->new();
my $acl_classes = &readModuleConfigFile($cm{classes_config});
my $pools = &readModuleConfigFile($cm{pools_config});
my @sorted_acl_classes = $objBandWidth->convertACL2Array($acl_classes);
my @sorted_pools = $objBandWidth->convertPool2Array($pools);
my ($aclList,@aclListAllow,@aclListDeny,$aclListBlocked,$poolList,@acls,%aclTypeURL_Regex);
my $logging = new Logging;
populateCfromConfig($logging->{this_module_code});
my $squid_settings = $logging->getSquidsSettings();
my $network_info = &getNetworkInfo;

my $ip_limit = new IPLimit;
populateCfromConfig($ip_limit->{this_module_code});
my $http_ip_limit_acl = $C->{$ip_limit->{this_module_code}}->{blocked_ip_list};
my @unlim_pools;


##########################################################################
#	Deleting *.txt files in ${acl_classes_folder}
##########################################################################
foreach (<$cm{classes_folder}/*.txt>) { unlink $_ || warn "Can't delete $_: $!\n" }

##########################################################################
#	Configuring ACL classes.
##########################################################################
foreach (@sorted_acl_classes)
{
	my ($label, $name, $type, $blocked) = ( $_->{label}, $_->{name}, $_->{type}, $_->{blocked} );

	# Replace \W|\s in ACL name with '_';
	$label =~ s/[\W\s]/_/g;

	next if (ref $_->{type} eq 'HASH' || $_->{label} eq 'HASH');

	# Add network mask to each IP from HTTP_ip_limit ACL;
	if ($_->{label} eq 'HTTP ip limit')
	{
		$_->{content} =~ s/(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\n/$1\/255\.255\.255\.255\n/g;
	} 

	my $fn = $cm{classes_folder}."/$label".$cm{classes_files_ext};
	my $content = ref $_->{content} eq 'HASH'?'':$_->{content};
	overwriteFile($fn,$content);

	if ($type eq 'url_regex')
	{
		# Creating hash with ACL type 'url_regex' and ACL name as key. We use it when configure POOLs.
		$aclTypeURL_Regex{$name} = '1';

		$name = $name.'_url';
		push(@acls, { $label => {qq|acl $name url_regex -i \"$fn\"| => $blocked} });
		$name =~ s/(\w+)_url/$1_ref/;
		push(@acls, { $label => {qq|acl $name referer_regex -i \"$fn\"| => $blocked} });
	}
	elsif ($type eq 'urlpath_regex')
	{
		push(@acls, { $label => {qq|acl $name urlpath_regex -i \"$fn\"| => $blocked} });
	}
	elsif ($type eq 'src')
	{
		push(@acls, { $label => {qq|acl $name src \"$fn\"| => $blocked} });
	}
	else
	{
		logModuleError("Undefined acl type '$type' of $label")
	}
}

foreach(@acls)
{
	foreach my $acl(values %{$_})
	{
		while ( my($acl,$is_blocked) = each(%$acl) )
		{
			$aclList .= "$acl\n";

			$acl =~ /^\w{3}\s(\w+)\s/;
			my $acl_name = $1;
			if ($is_blocked eq '0')
			{
				push(@aclListAllow,$acl_name);
			}
			elsif ($is_blocked eq '1')
			{
				push(@aclListDeny,$acl_name);
			}
		}
	}
}

##########################################################################
#	Configuring POOLS.
##########################################################################
my $pool_num = '0';

foreach (@sorted_pools)
{
	my(@aclClassess4pool);

	$pool_num++;

	if (exists($_->{content}->{name}))
	{
		push(@aclClassess4pool, $_->{content}->{name});
	}
	else
	{
		foreach my $acl_name (keys %{$_->{content}})
		{
			push(@aclClassess4pool, $acl_name);
		}
	}

	my $pool_speed = $_->{speed};
	if ($pool_speed ne '-1') { $pool_speed *= 1024 }

	my $acl_list = join(' ', @aclClassess4pool);

	my $delay_access;
	foreach (@aclClassess4pool)
	{
		if (exists $aclTypeURL_Regex{$_})
		{ 
			$_ = $_.'_url';
			$_ =~ /^(\w+)_url$/;
			$delay_access .= "delay_access $pool_num allow $_\n";
			$delay_access .= "delay_access $pool_num allow $1"."_ref\n";
			if ($pool_speed eq '-1')
			{
				push @unlim_pools, $1."_ref";
				push @unlim_pools, $_;
			}
		} 
		else 
		{
			$delay_access .= "delay_access $pool_num allow $_\n";
			if ($pool_speed eq '-1')
			{
				push @unlim_pools, $_;
			}

		}

	}

	my $current_pool = "delay_class $pool_num 1\n".$delay_access."delay_access $pool_num deny all\ndelay_parameters $pool_num $pool_speed/$pool_speed\n\n";
	$poolList .= $current_pool

}



foreach my $blocked_acl (@aclListDeny)
{
	if ($blocked_acl eq $http_ip_limit_acl)
	{
		$aclListBlocked .= 'http_access deny '."$blocked_acl".($#unlim_pools > -1?" !".join(" !",@unlim_pools):'')."\n";
	}
	else
	{
		$aclListBlocked .= 'http_access deny '."$blocked_acl\n";
	}
}



foreach my $v (values %$squid_settings)
{

##########################################################################
# We make backup of squid.conf every time when saving changes in acl.xml
##########################################################################

backupUserConfigFiles($v->{config});

##########################################################################
#	Modification squid.conf
##########################################################################

	open(FILE, "+<$v->{config}") || die "Can not open $v->{config}: $!\n";
	undef $/;
	my $content = <FILE>;

	################################
	# Configuration ACL our_network
	################################

	my ($acl_our_net_exists, $acl_our_net_enabled);

	if ( $content =~ /(acl\s$cm{our_net_name}\ssrc(\d|\.|\/|\s)+)\n/ )
	{
		my $pattern = $1;
		$pattern =~ s/\n+//;
    	if ( $pattern !~ /acl\s$cm{our_net_name}\ssrc.+$network_info->{network}\/($CIDR->{$network_info->{cidr}}->{network_mask}|$network_info->{cidr})/ )
		{
			$content =~ s/$pattern/$pattern $network_info->{network}\/$network_info->{cidr}/;
		}
		$acl_our_net_exists = '1';
	}

	if ( $content =~ /\nhttp_access allow $cm{our_net_name}/ ) { $acl_our_net_enabled = '1' }

	###################################

	$pool_num++;
	my $default_pool_speed = $cm{default_speed};
	$default_pool_speed *= 1024 if ($default_pool_speed ne '-1');
	my $default_pool = "delay_class $pool_num 1\ndelay_access $pool_num allow $cm{our_net_name}\ndelay_access $pool_num deny all\ndelay_parameters $pool_num $default_pool_speed\/$default_pool_speed\n";
	$poolList .= $default_pool;

	$content =~ /.+\n(#{50}\n#\sStart\sTrafficPanel\s\w{7}\n#{50})(\n.+\n)(#{50}\n#\sEnd\sTrafficPanel\s\w{7}\n#{50})\n.+/s;
	my(@splitted_file);

	if ($1 && $3)
	{

	@splitted_file = split(/($1|$3)/, $content);
	seek(FILE,0,0) || die "Seeking: $!", "\n";
	print(FILE @splitted_file[0,1], "\n" x 2,
	$aclList, "\n",
	"delay_pools $pool_num", "\n" x 2,
	$poolList, "\n",
	$aclListBlocked, "\n",
	@splitted_file[3,4]);

	}

	else
	{

	@splitted_file = split(/(# INSERT YOUR OWN RULE\(S\) HERE TO ALLOW ACCESS FROM YOUR CLIENTS)/,$content);
	if ( $#splitted_file > 0 )
	{
	seek(FILE,0,0) || die "Seeking: $!","\n";
	print(FILE @splitted_file[0,1], "\n" x 2);

	unless ($acl_our_net_exists) { print(FILE "acl $cm{our_net_name} src $network_info->{network}", "\n" x 2) }
	print(FILE '#' x 50, "\n", '# Start TrafficPanel section', "\n", '#' x 50, "\n" x 2,
		$aclList, "\n",
		"delay_pools $pool_num","\n" x 2,
		$poolList,"\n",
		$aclListBlocked,"\n",
		'#' x 50, "\n", '# End TrafficPanel section', "\n", '#' x 50, "\n");

	unless ($acl_our_net_enabled) { print(FILE "\nhttp_access allow $cm{our_net_name}") }

	print FILE $splitted_file[2];
	}

	else
		{
			print "Can not recognize squid config file.";
			exit;
		}
	}
	truncate(FILE, tell(FILE)) || die "Truncating: $!\n";
	close(FILE) || die "Can't close $v->{config}: $!\n";

	# Reconfiguring squid.
	run_twm_script("$cm{reconfigure_squid} $v->{config}", $mc);

}

__END__
